﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Design;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;


namespace Marmat.Forms
{

    /// <summary>
    /// 必填组件 
    /// </summary>
    [ProvideProperty("Open", typeof(Control))]
    [ProvideProperty("PropertyName", typeof(Control))]
    [ProvideProperty("ErrorText", typeof(Control))]
    public partial class RequiredComponent : IExtenderProvider, ISupportInitialize
    {
        private readonly Hashtable _propertyNameTable = new Hashtable();
        private readonly Hashtable _openTable = new Hashtable();
        private readonly Hashtable _errorText = new Hashtable();
        private readonly ErrorProvider _errorProvider = new ErrorProvider();

        /// <summary>
        /// 验证控件的值时触发的事件。
        /// </summary>
        public event EventHandler<RequiredComponentVerifyEventArgs> VerifyControlValuing;

        /// <summary>
        /// 验证控件需要变更样式时触发。
        /// </summary>
        public event EventHandler<RequiredComponentStyleEventArgs> StyleChanged;

        private bool m_AutoStyle;

        /// <summary>
        /// 获取或设置是否自动开启必填样式。
        /// </summary>
        /// <returns></returns>
        [DefaultValue(false)]
        [Category("样式")]
        [Description("获取或设置是否自动开启必填样式。")]
        public bool AutoStyle
        {
            get
            {
                return this.m_AutoStyle;
            }

            set
            {
                this.m_AutoStyle = value;
            }
        }

        /// <summary>
        /// 移除必填组件。
        /// </summary>
        /// <param name="control"></param>
        public void Remove(Control control)
        {
            this.SetOpen(control, false);
            this.SetPropertyName(control, null);
        }

        /// <summary>
        /// 验证必填组件是否验证通过。
        /// </summary>
        /// <returns></returns>
        public bool Verify()
        {
            this._errorProvider.Clear();
            bool result = true;
            foreach (Control control in this.GetControlCollection())
            {
                bool returnValue = true;
                if (this.GetOpen(control))
                {
                    if (control is IRequiredComponentSupport)
                    {
                        IRequiredComponentSupport support = (IRequiredComponentSupport)control;
                        returnValue = support.Verify();
                    }
                }
                else if (this._propertyNameTable.ContainsKey(control))
                {
                    returnValue = this.verifyControl(control, Convert.ToString(this._propertyNameTable[control]));
                }

                if (!returnValue)
                {
                    string errorText = this.GetErrorText(control);
                    if (string.IsNullOrEmpty(errorText))
                        errorText = "此处的值不能为空!";
                    this._errorProvider.SetError(control, errorText);
                    result = false;
                }
                else
                {
                    var arg = new RequiredComponentVerifyEventArgs(control) { Message = this.GetErrorText(control) };
                    VerifyControlValuing?.Invoke(this, arg);
                    if (arg.Cancel == true)
                    {
                        this._errorProvider.SetError(control, arg.Message);
                        result = false;
                    }
                }
            }

            return result;
        }

        private bool verifyControl(Control control, string propertyName)
        {
            bool result = true;
            var member = control.GetType().GetMember(propertyName).FirstOrDefault();
            Type memberType = null;
            object value = null;
            if (member is FieldInfo)
            {
                value = ((FieldInfo)member).GetValue(control);
                memberType = ((FieldInfo)member).FieldType;
            }
            else if (member is PropertyInfo)
            {
                value = ((PropertyInfo)member).GetValue(control);
                memberType = ((PropertyInfo)member).PropertyType;
            }

            if (value is null || ReferenceEquals(value, DBNull.Value) || ReferenceEquals(memberType, typeof(string)) && string.IsNullOrEmpty(Convert.ToString(value)) || ReferenceEquals(memberType, typeof(DateTime)) && value is null)
            {
                result = false;
            }
            return result;
        }

        /// <summary>
        /// 获取控件是否开启必填模式
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        [Browsable(true)]
        [DefaultValue(false)]
        [Category("必填")]
        [Description("是否开启必填模式。")]
        public bool GetOpen(Control control)
        {
            bool value = Convert.ToBoolean(this._openTable[control]);
            return value;
        }

        /// <summary>
        /// 设置控件是否开启必填模式
        /// </summary>
        /// <param name="control"></param>
        /// <param name="value"></param>
        public void SetOpen(Control control, bool value)
        {
            if (value == false)
            {
                if (this._openTable.ContainsKey(control))
                {
                    this._openTable.Remove(control);
                }
            }
            else
            {
                this._openTable[control] = value;
            }
        }

        /// <summary>
        /// 获取设置的属性名称
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        [Browsable(true)]
        [DefaultValue("")]
        [Category("必填")]
        [Description("需要判断的属性名称。")]
        [Editor(typeof(RequiredComponentUITypeEditor), typeof(UITypeEditor))]
        public string GetPropertyName(Control control)
        {
            string Value = Convert.ToString(this._propertyNameTable[control]);
            return Value;
        }

        /// <summary>
        /// 设置需要验证的属性名称。
        /// </summary>
        /// <param name="control"></param>
        /// <param name="value"></param>
        public void SetPropertyName(Control control, string value)
        {
            if (!string.IsNullOrEmpty(value)) // 要保存配置
            {
                this._propertyNameTable[control] = value;
            }
            else if (this._propertyNameTable.ContainsKey(control))
            {
                this._propertyNameTable.Remove(control);
            }
        }

        private Control[] GetControlCollection()
        {
            var collection = new List<Control>();
            collection.AddRange(this._openTable.Keys.OfType<Control>().ToArray());
            collection.AddRange(this._propertyNameTable.Keys.OfType<Control>().ToArray());
            return collection.Distinct().ToArray();
        }

        /// <summary>
        /// 获取验证不通过的错误提示
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        [Browsable(true)]
        [DefaultValue("")]
        [Category("必填")]
        [Description("验证不通过的错误提示。")]
        [Editor(typeof(RequiredComponentUITypeEditor), typeof(UITypeEditor))]
        public string GetErrorText(Control control)
        {
            string value = Convert.ToString(this._errorText[control]);
            return value;
        }

        /// <summary>
        /// 设置验证不通过的错误提示
        /// </summary>
        /// <param name="control"></param>
        /// <param name="value"></param>
        public void SetErrorText(Control control, string value)
        {
            if (!string.IsNullOrEmpty(value)) // 要保存配置
            {
                this._errorText[control] = value;
            }
            else if (this._errorText.ContainsKey(control))
            {
                this._errorText.Remove(control);
            }
        }

        /// <summary>
        /// 使用统一的颜色标记必填组件的背景颜色
        /// </summary>
        public void OpenStyle()
        {
            var collection = this.GetControlCollection();
            foreach (Control control in collection)
            {
                var args = new RequiredComponentStyleEventArgs(control, true);
                this.StyleChanged?.Invoke(this, args);
                if (!args.Cancel)
                {
                    if (control is IRequiredComponentSupport support)
                    {
                        support.OpenStyle();
                    }
                }
            }
        }

        /// <summary>
        /// 恢复控件的默认颜色
        /// </summary>
        public void CloseStyle()
        {
            var collection = this.GetControlCollection();
            foreach (Control control in collection)
            {
                var args = new RequiredComponentStyleEventArgs(control, false);
                StyleChanged?.Invoke(this, args);
                if (!args.Cancel)
                {
                    if (control is IRequiredComponentSupport)
                    {
                        IRequiredComponentSupport support = (IRequiredComponentSupport)control;
                        support.CloseStyle();
                    }
                }
            }
        }

        bool IExtenderProvider.CanExtend(object extendee)
        {
            return extendee is Control;
        }

        public virtual void BeginInit()
        {
        }

        public virtual void EndInit()
        {
            if (!this.DesignMode && this.AutoStyle)
            {
                this.OpenStyle();
            }
        }
    }
}